package com.kmxd.ams.core.mybatisplus;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.kmxd.ams.core.common.annotation.DataScope;
import com.kmxd.ams.core.common.bo.LoginUser;
import com.kmxd.ams.core.common.enums.DataScopeTypeEnum;
import com.kmxd.ams.core.util.DynamicTableNameUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import java.util.Objects;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import net.sf.jsqlparser.schema.Column;

/**
 * 自定义数据权限
 *
 * @author admin
 */
@Slf4j
public class CustomDataPermissionHandler implements DataPermissionHandler {
  /** 角色过滤数据拦截 */
  public static final String MANAGE_STATUS_COLUMN = "manage_status";

  /** 修改用户 */
  public static final String UPDATE_BY_COLUMN = "update_by";

  /** 状态 */
  public static final String STATUS_COLUMN = "status";

  /**
   * 构建过滤条件
   *
   * @param user 当前登录用户
   * @param where 当前查询条件
   * @return 构建后查询条件
   */
  public static Expression dataScopeFilter(LoginUser user, DataScope data, Expression where) {
    String tableAlias =
        ObjectUtil.equals(DataScopeTypeEnum.ARCHIVES.getType(), data.type().getType())
            ? DynamicTableNameUtil.getTableName()
            : data.tableAlias();
    String userColumnName = data.userColumnName();
    String deptColumnName = data.deptColumnName();
    String fondsColumnName = data.fondsColumnName();
    Expression expression = null;
    // 兼职人员是否可以互相查看数据 true可以相互看，false 不可以 20231010新版部门数据相互查看
    boolean dept_user = false;

    // 全部权限
    if (ObjectUtil.equals(user.getRoleType(), DataScopeTypeEnum.ALL.getType())) {
      return where;
    }
    // 个人数据
    // select * from f1_1_document t WHERE t.create_by = 1 or (update_by = 1 and manage_status = 2)
    // or (`status` = 7 and manage_status = 2)
    if (ObjectUtil.equals(user.getRoleType(), DataScopeTypeEnum.USER.getType())) {
      EqualsTo equalsTo = new EqualsTo();
      equalsTo.setLeftExpression(buildColumn(tableAlias, userColumnName));
      equalsTo.setRightExpression(new LongValue(user.getUserId()));

      NotEqualsTo notEqualsTo = new NotEqualsTo();
      notEqualsTo.setLeftExpression(buildColumn(tableAlias, MANAGE_STATUS_COLUMN));
      notEqualsTo.setRightExpression(new LongValue(2L));

      // S7(7, "提交中"),
      EqualsTo equalsToStatus = new EqualsTo();
      equalsToStatus.setLeftExpression(buildColumn(tableAlias, STATUS_COLUMN));
      equalsToStatus.setRightExpression(new LongValue(7L));

      Parenthesis parenthesisUser1 = new Parenthesis(new AndExpression(equalsTo, notEqualsTo));
      Parenthesis parenthesisUser2 = new Parenthesis(new AndExpression(equalsTo, equalsToStatus));
      Expression expressionUser2 = new OrExpression(parenthesisUser1, parenthesisUser2);

      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, expressionUser2)
              : expressionUser2;
    }

    // 部门数据范围,兼职人员可相互看
    if (ObjectUtil.equals(user.getRoleType(), DataScopeTypeEnum.DEPT.getType()) && dept_user) {
      // 自己的
      EqualsTo equalsToUser = new EqualsTo();
      equalsToUser.setLeftExpression(buildColumn(tableAlias, userColumnName));
      equalsToUser.setRightExpression(new LongValue(user.getUserId()));

      // 个人创建的
      EqualsTo equalsToRoleUser = new EqualsTo();
      equalsToRoleUser.setLeftExpression(buildColumn(tableAlias, MANAGE_STATUS_COLUMN));
      equalsToRoleUser.setRightExpression(new LongValue(DataScopeTypeEnum.USER.getType()));

      // S7(7, "提交中"),
      EqualsTo equalsToStatus = new EqualsTo();
      equalsToStatus.setLeftExpression(buildColumn(tableAlias, STATUS_COLUMN));
      equalsToStatus.setRightExpression(new LongValue(7L));

      // 角色
      EqualsTo equalsToRole = new EqualsTo();
      equalsToRole.setLeftExpression(buildColumn(tableAlias, MANAGE_STATUS_COLUMN));
      equalsToRole.setRightExpression(new LongValue(user.getRoleType()));

      Parenthesis parenthesisUser1 =
          new Parenthesis(new AndExpression(equalsToUser, equalsToRoleUser));
      Parenthesis parenthesisRoles2 =
          new Parenthesis(new AndExpression(equalsToStatus, equalsToRole));

      //      Expression expressionUser1 = new OrExpression(parenthesisUser1, parenthesisUser1);
      Expression expressionUser2 = new OrExpression(parenthesisUser1, parenthesisRoles2);
      Expression expressionUser3 = new OrExpression(expressionUser2, equalsToRole);

      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, expressionUser3)
              : expressionUser3;
      // 过滤部门
      EqualsTo equalsToDept = new EqualsTo();
      equalsToDept.setLeftExpression(buildColumn(tableAlias, deptColumnName));
      equalsToDept.setRightExpression(new LongValue(user.getDeptId()));

      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, equalsToDept)
              : equalsToDept;
    }
    // 部门数据范围,兼职人员数据互通20231010使用版本
    if (ObjectUtil.equals(user.getRoleType(), DataScopeTypeEnum.DEPT.getType()) && !dept_user) {
      // 角色
      EqualsTo equalsToRole = new EqualsTo();
      equalsToRole.setLeftExpression(buildColumn(tableAlias, MANAGE_STATUS_COLUMN));
      equalsToRole.setRightExpression(new LongValue(user.getRoleType()));

      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, equalsToRole)
              : equalsToRole;
      // 过滤部门
      EqualsTo equalsToDept = new EqualsTo();
      equalsToDept.setLeftExpression(buildColumn(tableAlias, deptColumnName));
      equalsToDept.setRightExpression(new LongValue(user.getDeptId()));

      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, equalsToDept)
              : equalsToDept;
    }
    // 全宗范围
    if (ObjectUtil.equals(user.getRoleType(), DataScopeTypeEnum.FONDS.getType())) {
      EqualsTo equalsToFonds = new EqualsTo();
      equalsToFonds.setLeftExpression(buildColumn(tableAlias, fondsColumnName));
      equalsToFonds.setRightExpression(new LongValue(user.getFondsId()));
      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, equalsToFonds)
              : equalsToFonds;
    }

    //   并且添加字段角色类型
    //    采集人员，新建数据自己看自己
    //    兼职人员，新建  自己看自己 采集员提交的
    //    档案管理员，新建数据可直接看 -兼职档案员移交后的

    if (ObjectUtil.equals(user.getRoleType(), DataScopeTypeEnum.FONDS.getType())) {
      EqualsTo equalsToRole = new EqualsTo();
      equalsToRole.setLeftExpression(buildColumn(tableAlias, MANAGE_STATUS_COLUMN));
      equalsToRole.setRightExpression(new LongValue(user.getRoleType()));
      expression =
          ObjectUtils.isNotEmpty(expression)
              ? new AndExpression(expression, equalsToRole)
              : equalsToRole;
    }

    return ObjectUtils.isNotEmpty(where)
        ? new AndExpression(where, new Parenthesis(expression))
        : expression;
  }

  /**
   * 构建Column
   *
   * @param tableAlias 表别名
   * @param columnName 字段名称
   * @return 带表别名字段
   */
  public static Column buildColumn(String tableAlias, String columnName) {
    if (StringUtils.isNotEmpty(tableAlias)) {
      columnName = tableAlias + "." + columnName;
    }
    return new Column(columnName);
  }

  @Override
  @SneakyThrows
  public Expression getSqlSegment(Expression where, String mappedStatementId) {
    Class<?> clazz =
        Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")));
    String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
    DataScope dataScope =
        AnnotationUtil.getAnnotation(
            ReflectUtil.getMethodByName(clazz, methodName), DataScope.class);
    if (Objects.isNull(dataScope)) {
      return where;
    }
    LoginUser loginUser = SecurityUtil.getLoginUser();
    if (Objects.isNull(loginUser) || SecurityUtil.isRootGroup()) {
      return where;
    }
    return dataScopeFilter(loginUser, dataScope, where);
  }
}
